﻿using System;

namespace System.Collections
{
    /// <summary>
    /// 树结构帮助类
    /// </summary>
    public class TreeHelper
    {
        /// <summary>
        /// 将 DataTable 转换成树节点集合
        /// </summary>
        /// <param name="source"> 数据源 </param>
        /// <param name="idColumn"> 编码列名 </param>
        /// <param name="parentColumn"> 父编码列名 </param>
        /// <param name="rootAction"> 获取根节点数据的委托 </param>
        /// <param name="convertAction"> 转换委托 </param>
        /// <returns></returns>
        public static System.Collections.Generic.List<System.Windows.Forms.TreeNode> Parse(System.Data.DataTable source, string idColumn, string parentColumn, System.Converter<System.Data.DataTable, System.Data.DataRow[]> rootAction = null, Action<System.Windows.Forms.TreeNode, System.Data.DataRow> convertAction = null)
        {
            var nodes = new System.Collections.Generic.List<System.Windows.Forms.TreeNode>();
            //  验证数据源
            if (source != null && source.Rows.Count > 0 && source.Columns.Contains(idColumn) && source.Columns.Contains(parentColumn))
            {
                System.Data.DataRow[] rootRows = null;
                //  判断根节点委托是否存在
                if (rootAction != null)
                    rootRows = rootAction.Invoke(source);
                else
                {
                    string sql = string.Format("[{0}] IS NULL OR [{0}]=NULL OR [{0}]=''", parentColumn);
                    //  获取根节点数据
                    rootRows = source.Select(sql);
                }
                //  验证根节点数据
                if (rootRows != null && rootRows.Length > 0)
                {
                    //  声明递归委托
                    Action<System.Windows.Forms.TreeNode, System.Data.DataRow> findAction = null;
                    //  定义查找方法
                    findAction = new Action<System.Windows.Forms.TreeNode, System.Data.DataRow>((parent, model) =>
                    {
                        //  创建新节点
                        var newNode = new System.Windows.Forms.TreeNode() { Tag = model };
                        //  查找当前节点的子节点
                        var childNodes = source.Select(string.Format("[{0}]='{1}'", parentColumn, model[idColumn] as string));
                        //  验证子节点
                        if (childNodes != null && childNodes.Length > 0)
                        {
                            for (int i = 0; i < childNodes.Length; i++)
                            {
                                findAction.Invoke(newNode, childNodes[i]);
                            }
                        }
                        //  验证父节点
                        if (convertAction != null)
                            convertAction.Invoke(newNode, model);
                        //  如果没有父节点，则添加到集合中
                        if (parent == null)
                            nodes.Add(newNode);
                        else
                            parent.Nodes.Add(newNode);
                    });
                    //  从根节点开始递归
                    for (int i = 0; i < rootRows.Length; i++)
                    {
                        findAction.Invoke(null, rootRows[i]);
                    }
                }
            }
            return nodes;
        }

        /// <summary>
        /// TreeInfo 集合转换成树节点集合
        /// </summary>
        /// <param name="source"> 数据源 </param>
        /// <param name="convert"> 转换委托 </param>
        /// <returns></returns>
        public static System.Collections.Generic.List<System.Windows.Forms.TreeNode> Parse(System.Collections.Generic.List<TreeInfo> source, Action<System.Windows.Forms.TreeNode, TreeInfo> convert)
        {
            //  创建控件节点集合
            var nodes = new System.Collections.Generic.List<System.Windows.Forms.TreeNode>();
            //  验证数据集合
            if (source != null && source.Count > 0)
            {
                //  获取根节点数据
                var roots = source.FindAll(x => string.IsNullOrEmpty(x.ParentID));
                //  验证根节点数据
                if (roots != null && roots.Count > 0)
                {
                    //  声明递归委托
                    Action<System.Windows.Forms.TreeNode, TreeInfo> findAction = null;
                    //  定义查找方法
                    findAction = new Action<System.Windows.Forms.TreeNode, TreeInfo>((parent, model) =>
                    {
                        //  创建新节点
                        var newNode = new System.Windows.Forms.TreeNode() { Text = model.Name, Tag = model };
                        //  查找当前节点的子节点
                        var childNodes = source.FindAll(y => y.ParentID == model.ID);
                        //  验证子节点
                        if (childNodes != null && childNodes.Count > 0)
                            childNodes.ForEach(y => { findAction.Invoke(newNode, y); });
                        //  验证父节点
                        if (convert != null)
                            convert.Invoke(newNode, model);
                        //  如果没有父节点，则添加到集合中
                        if (parent == null)
                            nodes.Add(newNode);
                        else
                            parent.Nodes.Add(newNode);
                    });
                    //  从根节点开始递归
                    roots.ForEach(model =>
                    {
                        findAction.Invoke(null, model);
                    });
                }
            }
            return nodes;
        }

        /// <summary>
        /// 树结构信息
        /// </summary>
        public class TreeInfo
        {
            /// <summary>
            /// 编码
            /// </summary>
            public string ID { get; set; }

            /// <summary>
            /// 名称
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// 父级编码
            /// </summary>
            public string ParentID { get; set; }

            /// <summary>
            /// 绑定的数据
            /// </summary>
            public object Tag { get; set; }
        }
    }
}
